﻿/*
 * Created by SharpDevelop.
 * User: issuser
 * Date: 2010-9-21
 * Time: 14:55
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

using NLite.ComponentModel;
using NLite.Domain;
using NLite.Reflection;

namespace NLite.Data
{
	public interface IObjectManager<TItem>: IEnumerable<TItem> where TItem : IEntity
	{
		IEnumerable<TItem> Inserted {get;}
		IEnumerable<TItem> Deleted {get;}
		IEnumerable<KeyValuePair<string, object>[]> Updated {get;}
		void Insert( TItem item );
		void Delete( TItem item );
		void SubmitChanges();
	}
	
	
	
	[Serializable]
	public class ObjectManager<TItem>: IEnumerable<TItem> where TItem : IEntity
	{
		
		
		private List<TItem> items;
		private IDictionary<string, object>[] oldItems;
		
		private HashSet<TItem> inserted;
		private HashSet<TItem> deleted;
		
		
		public IEnumerable<TItem> Inserted {
			get { return inserted; }
		}
		public IEnumerable<TItem> Deleted {
			get { return deleted; }
		}
		public IEnumerable<KeyValuePair<string, object>[]> Updated {
			get {
				var updateItems =( from current in items
				                  from @old in oldItems
				                  where current.Id == (long)@old["Id"]
				                  select new KeyValuePair<IDictionary<string, object>, TItem> (@old,current))
					.ToArray();
				
				if(updateItems.Length == 0)
					yield break;
				else
				{
					var members =oldItems[0].Keys;
					foreach(var item in updateItems)
						yield return oldItems[0].Keys
							.Where(p=>p == "Id" || item.Key[p] != item.Value.GetProperty(p))
							.Select(p=> new KeyValuePair<string, object>(p,item.Value.GetProperty(p)))
							.ToArray();
				}
				
			}
		}
		
		private static Type ItemType;
		private static MemberInfo[] Properties;
		
		static ObjectManager() {
			ItemType = typeof( TItem );
			Properties = ItemType.GetMembers(BindingFlags.Instance | BindingFlags.Public)
				.Where(m=>m.MemberType == MemberTypes.Field || m.MemberType == MemberTypes.Property)
				.Where(m=>!m.HasAttribute<IgnoreAttribute>(true))
				.Select(m=>m)
				.ToArray();
				
		}
		
		public ObjectManager( IEnumerable<TItem> items ) {
			if ( items == null ) {
				throw new ArgumentNullException(
					"items",
					"Argument items is null."
				);
			}
			this.oldItems = items.Select(p=>Mapper.Map<TItem,IDictionary<string,object>>(p)).ToArray();
			this.items =items.ToList();
			
			this.inserted = new HashSet<TItem>();
			this.deleted = new HashSet<TItem>();
		}
		
		
		public void Insert( TItem item ) {
			if ( item == null ) {
				throw new ArgumentNullException( "item", "Parameter item is null." );
			}
			if ( this.deleted.Contains( item ) ) {
				throw new ArgumentException( "This item was already deleted.", "item" );
			}
			if ( this.items.Contains( item ) ) {
				throw new ArgumentException( "This item is already exists.", "item" );
			}
			this.items.Add( item );
			this.inserted.Add( item );
		}
		public void Delete( TItem item ) {
			if ( item == null ) {
				throw new ArgumentNullException( "item", "Parameter item is null." );
			}
			if ( !this.items.Remove( item ) ) {
				throw new ArgumentException( "This item is not found.", "item" );
			}
			if ( this.inserted.Remove( item ) ) {
				return;
			}
			
			this.deleted.Add( item );
		}
		
		public IEnumerator<TItem> GetEnumerator() {
			return this.items.GetEnumerator();
		}
		
		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
			return this.GetEnumerator();
		}
		
		public virtual void SubmitChanges()
		{
			this.oldItems = items.Select(p=>Mapper.Map<TItem,IDictionary<string,object>>(p)).ToArray();
			this.deleted.Clear();
			this.inserted.Clear();
		}
	}
}
